package club.hicode.daydayup.monitor;

import cn.hutool.core.util.StrUtil;
import com.sun.management.OperatingSystemMXBean;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LinuxProcessCollector implements ICollector {
	static final int CPUTIME = 5000;
	static final int PERCENT = 100;
	static final int FAULTLENGTH = 10;

	public MonitorInfoBean getMonitorInfoBean(MonitorInfoBean infoBean) throws Exception {
		int kb = 1024;
		long totalMemory = Runtime.getRuntime().totalMemory() / kb;
		long freeMemory = Runtime.getRuntime().freeMemory() / kb;
		long maxMemory = Runtime.getRuntime().maxMemory() / kb;
		OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
		String osName = System.getProperty("os.name");
		HashMap<String, Long> mems = getSystemMem();
		int avaliableprocs = osmxb.getAvailableProcessors();
		String hostName = getSystemHostName();
		ThreadGroup parentThread;
		for (parentThread = Thread.currentThread().getThreadGroup();
			 parentThread.getParent() != null; parentThread = parentThread.getParent())
			;
		int totalThread = parentThread.activeCount();
		double cpuRatio = 0;
		if (!osName.toLowerCase().startsWith("windows")) {
			cpuRatio = this.getCpuRatio(null);
		}

		if (cpuRatio < 0)
			Math.abs(cpuRatio);
		if (null == infoBean)
			infoBean = new MonitorInfoBean();
		infoBean.osName = osName;
		infoBean.freeMemory = freeMemory;
		infoBean.maxMemory = maxMemory;
		infoBean.totalMemory = totalMemory;
		infoBean.installPhysicalMemorySize = 0;
		infoBean.totalPhysicalMemorySize = mems.get("TotalVisibleMemorySize");
		infoBean.freePhysicalMemorySize = mems.get("FreePhysicalMemory");
		infoBean.totalVirtualMemorySize = mems.get("TotalVirtualMemorySize");
		infoBean.freeVirtualMemory = mems.get("FreeVirtualMemory");
		infoBean.totalSwapSpaceSize = mems.get("TotalSwapSpaceSize");
		infoBean.freeSpaceInPagingFiles = mems.get("FreeSpaceInPagingFiles");
		infoBean.SizeStoredInPagingFiles = mems.get("SizeStoredInPagingFiles");
		infoBean.totalThread = totalThread;
		infoBean.cpuRatio = cpuRatio;
		infoBean.avliaProcessCount = avaliableprocs;
		infoBean.hostName = hostName;
		infoBean.logicDiskInfos = readSystemLogicDiskInfo(infoBean);
		return infoBean;
	}

	public double getCpuRatio(String processName) {
		Process proc = null;
		double usage = 0.0;
		try {
			String procCmd = "top -b -n 1";
			proc = Runtime.getRuntime().exec(procCmd);
			proc.getOutputStream().close();
			BufferedReader ir = new BufferedReader(new InputStreamReader(proc.getInputStream()));
			ir.readLine();
			ir.readLine();
			String[] res = null;
			String line = ir.readLine();

			if (null != line) {
				/**
				 * Cpu(s):  0.9%us,  0.4%sy,  0.0%ni, 98.0%id,  0.5%wa,  0.0%hi,  0.1%si,  0.0%st
				 */
				res = line.split(",");
				if (res.length == 8) {
					line = getNum(res[3]);
					if (null != line)
						usage = 100.0 - Double.valueOf(line);
				}
			}
		} catch (Exception e0) {
			try {
				proc.getInputStream().close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return usage;
	}


	public static ProcessInfo readProcessNamePidsInfo(String processName, String pid) {
		ProcessInfo pidInfo = new ProcessInfo();
		Process proc = null;
		try {
			//String procCmd = "top -b -n 1 -p `pgrep "+processName+" | tr \"\\n\" \",\" | sed 's/,$//'`";
			String procCmd = "top -b -n 1";
			proc = Runtime.getRuntime().exec(procCmd);

			proc.getOutputStream().close();
			BufferedReader ir = new BufferedReader(new InputStreamReader(proc.getInputStream()));
			String line = null;
			boolean hasprcess = false;
			StringTokenizer tokenStat = null;
			while ((line = ir.readLine()) != null) {
				if (StrUtil.isBlank(line))
					continue;
				if (line.indexOf("COMMAND") > -1) {
					hasprcess = true;
				}
				if (hasprcess) {
					//PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
					tokenStat = new StringTokenizer(line);
					String pid0 = tokenStat.nextElement().toString();
					tokenStat.nextElement();
					tokenStat.nextElement();
					tokenStat.nextElement();
					String VIRT = tokenStat.nextElement().toString();
					String RES = tokenStat.nextElement().toString();
					tokenStat.nextElement();
					tokenStat.nextElement();
					String cpu = tokenStat.nextElement().toString();
					String memusage = tokenStat.nextElement().toString();
					tokenStat.nextElement();
					String comand = tokenStat.nextElement().toString();

					if (comand.equals(processName) || pid0.equals(pid)) {
						pidInfo.ProcessName = processName;
						pidInfo.ProcessId = Long.valueOf(pid0);
						pidInfo.PProcessId = Ppid(pidInfo.ProcessId);
						if (null != RES && RES.toLowerCase().endsWith("m"))
							pidInfo.memoryInuse = Double.valueOf(getNum(RES)) * 1024;
						else
							pidInfo.memoryInuse = Double.valueOf(getNum(RES));
						pidInfo.memoryUsage = Double.valueOf(getNum(memusage));
						if (null != VIRT && VIRT.toLowerCase().endsWith("m"))
							pidInfo.VirtualSize = Double.valueOf(getNum(VIRT)) * 1024;
						else
							pidInfo.VirtualSize = Double.valueOf(getNum(VIRT));
						pidInfo.cpuUsage = Double.valueOf(getNum(cpu));
					}
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				proc.getInputStream().close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return pidInfo;
	}

	public static long Ppid(long pid) {
		Process proc = null;
		long Ppid = -1;
		BufferedReader ir = null;
		try {
			//String procCmd = "top -b -n 1 -p `pgrep "+processName+" | tr \"\\n\" \",\" | sed 's/,$//'`";
			String procCmd = "ps -p " + pid + " -o ppid";
			proc = Runtime.getRuntime().exec(procCmd);
			proc.getOutputStream().close();
			ir = new BufferedReader(new InputStreamReader(proc.getInputStream()));
			String line = ir.readLine();
			if (line == null) {
				return -1;
			}
			int ppid_idx = line.indexOf("PPID");
			if (ppid_idx > -1) {
				while ((line = ir.readLine()) != null) {
					if (StrUtil.isBlank(line))
						continue;
					Ppid = Long.valueOf(getNum(line));
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != ir)
					ir.close();
			} catch (Exception e) {}
		}
		return Ppid;

	}

	public static List<LogicDiskInfo> readSystemLogicDiskInfo(MonitorInfoBean infoBean) {
		Process proc = null;
		MonitorInfoBean infoBeano = infoBean;
		List<LogicDiskInfo> logicDiskInfos = null;
		if (null != infoBeano) {
			infoBean.avliaLogicDiskCount = 0;
			logicDiskInfos = infoBean.logicDiskInfos;
		}
		if (null == logicDiskInfos) {
			logicDiskInfos = new ArrayList<LogicDiskInfo>();
		}
		try {
			/**
			 * Filesystem,1048576-blocks,Used,Available,Capacity,Mounted on
			 */
			String procCmd = "df -Pm";
			proc = Runtime.getRuntime().exec(procCmd);
			proc.getOutputStream().close();
			BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream()));
			String line = input.readLine();
			int logicdiskindx = 0;
			int createdLen = logicDiskInfos.size();
			LogicDiskInfo diskoinfo = null;
			long diskTotalSize = 0;
			long diskTotalFreeSize = 0;
			StringTokenizer tokenStat = null;
			while ((line = input.readLine()) != null) {
				if (StrUtil.isBlank(line))
					continue;
				if (createdLen > logicdiskindx) {
					diskoinfo = logicDiskInfos.get(logicdiskindx);
				} else {
					diskoinfo = new LogicDiskInfo();
					logicDiskInfos.add(diskoinfo);
				}
				logicdiskindx++;
				tokenStat = new StringTokenizer(line);
				diskoinfo.Caption = tokenStat.nextElement().toString();
				diskoinfo.Description = diskoinfo.Caption;
				diskoinfo.Size = Double.valueOf(tokenStat.nextElement().toString());
				diskTotalSize += diskoinfo.Size;
				tokenStat.nextElement();
				diskoinfo.FreeSpace = Double.valueOf(tokenStat.nextElement().toString());
				diskTotalFreeSize += diskoinfo.FreeSpace;
				tokenStat.nextElement();
				diskoinfo.DeviceID = tokenStat.nextElement().toString();
				diskoinfo.VolumeName = diskoinfo.DeviceID;
			}
			if (null != infoBeano) {
				infoBean.avliaLogicDiskCount = logicdiskindx;
				infoBean.diskTotalSize = diskTotalSize;
				infoBean.diskTotalFreeSize = diskTotalFreeSize;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				proc.getInputStream().close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return logicDiskInfos;
	}

	public static String getSystemHostName() {
		Process proc = null;
		String hostName = null;
		try {
			String procCmd = "hostname";
			proc = Runtime.getRuntime().exec(procCmd);
			proc.getOutputStream().close();
			InputStreamReader ir = new InputStreamReader(proc.getInputStream());
			LineNumberReader input = new LineNumberReader(ir);
			hostName = input.readLine();
			if (StrUtil.isBlank(hostName)) {
				hostName = null;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				proc.getInputStream().close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return hostName;
	}

	public static HashMap<String, Long> getSystemMem() {
		Process proc = null;
		HashMap<String, Long> meminfos = new HashMap<String, Long>();
		meminfos.put("FreePhysicalMemory", 0L);
		meminfos.put("FreeSpaceInPagingFiles", 0L);
		meminfos.put("FreeVirtualMemory", 0L);
		meminfos.put("SizeStoredInPagingFiles", 0L);
		meminfos.put("TotalSwapSpaceSize", 0L);
		meminfos.put("FreeSwapSpaceSize", 0L);
		meminfos.put("TotalVirtualMemorySize", 0L);
		meminfos.put("TotalVisibleMemorySize", 0L);
		BufferedReader bufReader = null;
		try {
        	/*
        	MemTotal:         494572 kB
			MemFree:           39204 kB
			Buffers:           14684 kB
			Cached:           144704 kB
			SwapCached:         1276 kB
			Active:           152028 kB
			Inactive:         174596 kB
			Active(anon):      67548 kB
			Inactive(anon):   104128 kB
			Active(file):      84480 kB
			Inactive(file):    70468 kB
			Unevictable:           0 kB
			Mlocked:               0 kB
			SwapTotal:       4095992 kB
			SwapFree:        4087444 kB
			Dirty:                24 kB
			Writeback:             0 kB
			AnonPages:        166068 kB
			Mapped:            47600 kB
			Shmem:              4432 kB
			Slab:              78372 kB
			SReclaimable:      20884 kB
			SUnreclaim:        57488 kB
			KernelStack:        2168 kB
			PageTables:        25676 kB
			NFS_Unstable:          0 kB
			Bounce:                0 kB
			WritebackTmp:          0 kB
			CommitLimit:     4343276 kB
			Committed_AS:     704940 kB
			VmallocTotal:   34359738367 kB
			VmallocUsed:      142256 kB
			VmallocChunk:   34359581660 kB
			HardwareCorrupted:     0 kB
			AnonHugePages:         0 kB
			HugePages_Total:       0
			HugePages_Free:        0
			HugePages_Rsvd:        0
			HugePages_Surp:        0
			Hugepagesize:       2048 kB
			DirectMap4k:        8192 kB
			DirectMap2M:      516096 kB
        	 */
			String procCmd = "cat /proc/meminfo";
			proc = Runtime.getRuntime().exec(procCmd);
			proc.getOutputStream().close();
			bufReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
			String line = bufReader.readLine();
			line = getNum(line);
			long MemTotal = null == line ? 0 : Long.valueOf(line);
			meminfos.put("TotalVisibleMemorySize", MemTotal);
			line = bufReader.readLine();
			line = getNum(line);
			long MemFree = null == line ? 0 : Long.valueOf(line);
			line = bufReader.readLine();
			line = getNum(line);
			long Buffers = null == line ? 0 : Long.valueOf(line);
			line = bufReader.readLine();
			line = getNum(line);
			long Cached = null == line ? 0 : Long.valueOf(line);
			long SwapTotal = 0L;
			long SwapFree = 0L;
			while (null != (line = bufReader.readLine())) {
				if (StrUtil.isBlank(line) && line.startsWith("SwapTotal")) {
					line = getNum(line);
					SwapTotal = null == line ? 0 : Long.valueOf(line);
					break;
				}
			}
			line = bufReader.readLine();
			line = getNum(line);
			SwapFree = null == line ? 0 : Long.valueOf(line);
			meminfos.put("TotalSwapSpaceSize", SwapTotal);
			meminfos.put("FreeSwapSpaceSize", SwapFree);
			long VmallocTotal = 0L;
			long VmallocUsed = 0L;
			while (null != (line = bufReader.readLine())) {
				//				if (!StringUtil.isTrimEmpty(line) && line.startsWith("VmallocTotal")) {
				if (StrUtil.isNotBlank(line) && line.startsWith("VmallocTotal")) {

					line = getNum(line);
					VmallocTotal = null == line ? 0 : Long.valueOf(line);
				}
			}
			line = bufReader.readLine();
			line = getNum(line);
			VmallocUsed = null == line ? 0 : Long.valueOf(line);
			meminfos.put("TotalVirtualMemorySize", VmallocTotal);
			meminfos.put("FreeVirtualMemory", VmallocTotal - VmallocUsed);
			meminfos.put("FreeSpaceInPagingFiles", MemFree + Cached + Buffers);
			meminfos.put("SizeStoredInPagingFiles", MemTotal + Cached + Buffers);
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				proc.getInputStream().close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return meminfos;
	}

	public static String getNum(String sStr) {
		Pattern p = Pattern.compile("\\d+\\.?\\d+");
		Matcher m = p.matcher(sStr);
		String num = null;
		if (m.find()) {
			num = m.group(0);
		}
		return num;
	}

	public static void main(String[] args) throws Exception {
		LinuxProcessCollector service = new LinuxProcessCollector();
		MonitorInfoBean monitorInfo = service.getMonitorInfoBean(null);
		System.out.println("主机名=" + monitorInfo.hostName);
		System.out.println("主机名IP=" + monitorInfo.IP);
		System.out.println("主机名系统名=" + monitorInfo.osName);
		System.out.println("cpu占有率=" + monitorInfo.cpuRatio);

		System.out.println("可使用核心内存=" + monitorInfo.totalMemory);
		System.out.println("剩余核心内存=" + monitorInfo.freeMemory);
		System.out.println("最大可使用核心内存=" + monitorInfo.maxMemory);

		System.out.println("操作系统=" + monitorInfo.osName);
		System.out.println("总的物理内存=" + monitorInfo.totalPhysicalMemorySize + "kb");
		System.out.println("剩余的物理内存=" + monitorInfo.freePhysicalMemorySize + "kb");

		System.out.println("总虚拟内存=" + monitorInfo.totalVirtualMemorySize + "kb");
		System.out.println("可用虚拟内存=" + monitorInfo.freeVirtualMemory + "kb");

		System.out.println("内存交换区大小=" + monitorInfo.totalSwapSpaceSize + "kb");

		System.out.println("内存总计=" + monitorInfo.SizeStoredInPagingFiles + "kb");
		System.out.println("可分配内存总计=" + monitorInfo.freeSpaceInPagingFiles + "kb");
		System.out.println("java线程总数=" + monitorInfo.totalThread + "kb");
		ProcessInfo prcess = readProcessNamePidsInfo("Xorg", null);
		System.out.println(
				prcess.ProcessName + "," + prcess.ProcessId + "," + prcess.PProcessId + "," + prcess.cpuUsage + ","
						+ prcess.memoryInuse / 1024 + "," + prcess.VirtualSize / 1024 + "," + prcess.memoryUsage);
		System.out.println("infoBean.getAvliaLogicDiskCount():" + monitorInfo.avliaLogicDiskCount);
		System.out.println("logicDiskInfos.size():" + monitorInfo.logicDiskInfos.size());

		System.out.println("DiskTotalSize:" + monitorInfo.diskTotalSize);
		System.out.println("TotalFreeSize:" + monitorInfo.diskTotalFreeSize);

		for (int i = 0; i < monitorInfo.avliaLogicDiskCount; i++) {
			LogicDiskInfo b = monitorInfo.logicDiskInfos.get(i);
			System.out.println(
					b.Caption + "," + b.Description + "," + b.DeviceID + "," + b.DriveType + "," + b.FileSystem + ","
							+ b.FreeSpace + "," + b.Size + "," + b.VolumeName);
		}
		final BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
		strin.readLine();
	}


}  
